package redisClient

import (
	"encoding/json"
	"fmt"
	"gitee.com/lv_baobao/gcore"
	"github.com/ahmetb/go-linq/v3"
	"github.com/go-redis/redis"
	"runtime"
	"time"
)

type FailoverClient struct {
	Client *redis.Client
}

func NewFailoverClient() IRedisClient {
	var client = &FailoverClient{}
	client.init()
	return client
}

func (r *FailoverClient) init() {
	redisConfig := gcore.NewAppSettingsHelper().GetAppConfig().Redis
	if redisConfig.PoolSize == 0 {
		redisConfig.PoolSize = runtime.NumCPU()
	}
	serverList := redisConfig.ServerList
	var addrList = make([]string, 0)
	linq.From(serverList).Select(func(i interface{}) interface{} {
		server := i.(gcore.RedisServer)
		return fmt.Sprintf("%s:%d", server.Host, server.Port)
	}).ToSlice(&addrList)
	if redisConfig.PoolSize == 0 {
		redisConfig.PoolSize = runtime.NumCPU()
	}
	fmt.Printf("redis poolsize %d", redisConfig.PoolSize)
	r.Client = redis.NewFailoverClient(&redis.FailoverOptions{
		SentinelAddrs: addrList,
		Password:      redisConfig.PassWord,
		MasterName:    redisConfig.MasterName,
		PoolSize:      redisConfig.PoolSize,
	})
}

func (r *FailoverClient) Get(key string, objPtr interface{}) error {
	bytes, err := r.Client.Get(key).Bytes()
	if err != nil {
		return err
	}
	err = json.Unmarshal(bytes, objPtr)
	if err != nil {
		return err
	}
	return nil
}

func (r *FailoverClient) Incr(key string) error {
	return r.Client.Incr(key).Err()
}

func (r *FailoverClient) Add(key string, value interface{}, duration time.Duration) error {
	bytes, err := json.Marshal(value)
	if err != nil {
		return err
	}
	return r.Client.Set(key, bytes, duration).Err()
}

func (r *FailoverClient) Del(key string) error {
	return r.Client.Del(key).Err()
}

func (r *FailoverClient) Expire(key string, duration time.Duration) error {
	return r.Client.Expire(key, duration).Err()
}

func (r *FailoverClient) LPush(key string, value interface{}) (error, int64) {
	bytes, err := json.Marshal(value)
	if err != nil {
		return err, 0
	}
	push := r.Client.LPush(key, bytes)
	return push.Err(), push.Val()
}

func (r *FailoverClient) LRange(key string, start int64, stop int64) ([]string, error) {
	push := r.Client.LRange(key, start, stop)
	return push.Val(), push.Err()
}

func (r *FailoverClient) LIndex(key string, index int64) (string, error) {
	push := r.Client.LIndex(key, index)
	return push.Val(), push.Err()
}

func (r *FailoverClient) LSet(key string, index int64, value interface{}) error {
	cmd := r.Client.LSet(key, index, value)
	return cmd.Err()
}

func (r *FailoverClient) LRem(key string, count int64, value interface{}) error {
	cmd := r.Client.LRem(key, count, value)
	return cmd.Err()
}

func (r *FailoverClient) LTrim(key string, start int64, stop int64) error {
	cmd := r.Client.LTrim(key, start, stop)
	return cmd.Err()
}

func (r *FailoverClient) HSet(key string, field string, value interface{}) error {
	bytes, err := json.Marshal(value)
	if err != nil {
		return err
	}
	cmd := r.Client.HSet(key, field, bytes)
	return cmd.Err()
}

func (r *FailoverClient) HGet(key string, field string, objPtr interface{}) error {
	cmd := r.Client.HGet(key, field)
	if cmd.Err() != nil {
		return cmd.Err()
	}
	bytes, err := cmd.Bytes()
	if err != nil {
		return err
	}
	err = json.Unmarshal(bytes, objPtr)
	return err
}

func (r *FailoverClient) Pipeline() redis.Pipeliner {
	return r.Client.Pipeline()
}
